#include "stdafx.h"
#include "FolderHidingToolApp.h"
#include "FolderHidingToolDlg.h"
#include "WatchDir.h"
#include "RulesProcessingUserMode.h"
#include "Interface.h"
#include "Utility.h"
#include <WinIoCtl.h>

const wchar_t wsKeyValue[] = L"System\\ControlSet001\\Services\\FileHidingFilter\\Rules";
const wchar_t wsKeyName[] = L"HideFolderAction";
const wchar_t wsEmptyFolder[] = L"New";
const wchar_t wsEmptyList[] = L"\0\0";

static UINT indicators[] =
{
    ID_TOOL_INDICATOR,
    ID_PATH_INDICATOR
};

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CMultiSZObserver: public IMultiSZObserver
{
public:
    CMultiSZObserver(CListCtrl *pList)
    {
        pMyList = pList;
    }

    void OnMultiSZItemFound(const std::wstring& wsMultiSZItem)
    {
        LPCTSTR lpItem = wsMultiSZItem.c_str();

        int nNumber = pMyList->GetItemCount();
        
        pMyList->InsertItem(nNumber, lpItem); 
    }

    void ClearVector()
    {
        vectWStr.clear();
    }

    const std::vector<std::wstring>& GetVector()
    {
        int nCount = pMyList->GetItemCount();

        WCHAR szBuffer[MAX_PATH];

        for(int i = 0; i < nCount; ++i)
        {
            std::wstring wsItem;

            pMyList->GetItemText(i, 0, szBuffer, sizeof(szBuffer));

            vectWStr.push_back(szBuffer);
        }

        return vectWStr;
    }

private:
    CMultiSZObserver(const CMultiSZObserver&);
    CMultiSZObserver& operator =(const CMultiSZObserver&);

    CListCtrl *pMyList;
    std::vector<std::wstring> vectWStr;
};

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


CFolderHidingToolDlg::CFolderHidingToolDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFolderHidingToolDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFolderHidingToolDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_TREE, m_ctrlTree);
    DDX_Control(pDX, IDC_LIST, m_ctrlList);
}

BEGIN_MESSAGE_MAP(CFolderHidingToolDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_WM_SIZE()
	//}}AFX_MSG_MAP
    ON_NOTIFY(TVN_SELCHANGED, IDC_TREE, &CFolderHidingToolDlg::OnTvnSelchangedTree)
    ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREE, &CFolderHidingToolDlg::OnTvnItemexpandingTree)
    ON_BN_CLICKED(IDC_HIDE_BUTTON, &CFolderHidingToolDlg::OnBnClickedHideButton)
    ON_BN_CLICKED(IDC_SHOW_BUTTON, &CFolderHidingToolDlg::OnBnClickedShowButton)
    ON_BN_CLICKED(IDC_APPLY_BUTTON, &CFolderHidingToolDlg::OnBnClickedApplyButton)
    ON_MESSAGE(MYMESS_CALL_VOLCOUNT_CHANGE, AddNewVolume)
    ON_MESSAGE(MYMESS_CALL_VOL_CHANGE, OnRefreshVolumeList)
    ON_MESSAGE(MYMESS_CALL_DIR_CHANGE, OnRefreshTree)
    ON_COMMAND(ID_HIDE_EXIT,OnMainMenuExit)
    ON_COMMAND(ID_HELP_ABOUTPROGRAM,OnMainMenuAbout)
END_MESSAGE_MAP()


// CTreeDlg message handlers

BOOL CFolderHidingToolDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

    m_wndMainMenu.LoadMenu(IDR_MAINMENU);
    ASSERT(m_wndMainMenu);

    SetMenu(&m_wndMainMenu);

    m_bar.Create(this);
    m_bar.SetIndicators(indicators,2);

    CRect rect;
    GetClientRect(&rect);

    m_bar.SetPaneInfo(0, ID_PATH_INDICATOR, SBPS_NORMAL, rect.Width()-100);      
    m_bar.SetPaneInfo(1, ID_TOOL_INDICATOR, SBPS_STRETCH, 0);

    RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_RESIZE_BAR, ID_TOOL_INDICATOR);

    CStringArray arString;

    if(GetVolumesList(arString))
    {
        int nCount = arString.GetCount();

        m_imageList.Create(16, 16, ILC_MASK | ILC_COLOR32, nCount, 20);
        m_ctrlTree.SetImageList(&m_imageList, TVSIL_NORMAL);

        if(!GetFolderIcon(arString))
        {
            m_imageList.Add(AfxGetApp()->LoadIcon(IDI_ICONFOLDER));
        }

        for(int i = 0; i < nCount; ++i)
        {
            HTREEITEM hItem = m_ctrlTree.InsertItem(arString[i], TVI_ROOT, TVI_SORT);

            FillTreeWithFolders(arString[i], hItem, false);
        }

        RefreshRootIconsAndNames(arString);
    }

    //Start watch volume thread
    ThreadParam* volparam = new ThreadParam;
    volparam->mDlg = m_hWnd;  
    AfxBeginThread(WaitForVolumeChange, volparam);
    volparam = 0;

    //Start watch volume notifications
    ThreadParam* dirparam = new ThreadParam;
    dirparam->mDlg = m_hWnd; 
    AfxBeginThread(WaitForDirectoryChange, dirparam);
    dirparam = 0;

    CMultiSZObserver observer(&m_ctrlList);
    
    try
    {
        EnumMultiSZValue(wsKeyValue, wsKeyName, &observer);
    }
    catch (std::runtime_error &e) 
    {
        std::string errorStr = e.what();

        if(errorStr == "Error key opening!" || errorStr == "Error value reading!")
        {
            HKEY hKeyMain = NULL;
            LONG lResult = RegCreateKeyW(HKEY_LOCAL_MACHINE, wsKeyValue, &hKeyMain);

            if(lResult != ERROR_SUCCESS)
            {
                MessageBox(L"Coudln't refresh list of hiden folders", L"Error", MB_OK | MB_ICONERROR);

                return FALSE;
            }

            KeyGuard keyGuard(hKeyMain);

        }
        else if(errorStr != "Error value reading!")
        {
            MessageBox(L"Coudln't refresh list of hiden folders", L"Error", MB_OK | MB_ICONERROR);

            return FALSE;
        }    
    }

    observer.OnMultiSZItemFound(wsEmptyList);

    try
    {
        WriteMultiSZValue(wsKeyValue, wsKeyName, observer.GetVector());
    }
    catch (...)
    {
        MessageBox(L"Coudln't refresh list of hiden folders", L"Error", MB_OK | MB_ICONERROR);

        return FALSE;
    }
    
    ClearRulesList();

	return TRUE;  
}

void CFolderHidingToolDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	CDialog::OnSysCommand(nID, lParam);
}

void CFolderHidingToolDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CFolderHidingToolDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CFolderHidingToolDlg::OnTvnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

    HTREEITEM hSel = m_ctrlTree.GetSelectedItem();

    CString sPath = GetTreePath(hSel);

    m_bar.SetPaneText(0, L"Folder: " + sPath);
    
    UpdateData(FALSE);

    *pResult = 0;
}

CString CFolderHidingToolDlg::GetTreePath( HTREEITEM hParent )
{
    CString sPath = L"";

    if(m_ctrlTree.GetNextItem(hParent, TVGN_PARENT) == NULL)
    {
        sPath = L"\\";
    }

    do
    {
        if(m_ctrlTree.GetNextItem(hParent, TVGN_PARENT) == NULL)
        {
            CString sDriveName = m_ctrlTree.GetItemText(hParent);
            int nCount = sDriveName.GetLength();

            if(sDriveName.Find('\\', nCount -1) == -1)
            {
                sPath = sDriveName.Mid(nCount - 3, 2) + sPath;
                break;
            }

            sDriveName.Delete(nCount -1);

            sPath = sDriveName + sPath;

            break;
        }
        
        sPath = L"\\" + m_ctrlTree.GetItemText(hParent) + sPath;

        hParent = m_ctrlTree.GetNextItem(hParent, TVGN_PARENT);

    }while(hParent != NULL);

    return sPath;
}

bool CFolderHidingToolDlg::FillTreeWithFolders(CString &sPath, HTREEITEM hItem, bool bFill)
{
    CStringArray arFolders;

    if(!GetFoldersInDirectory(sPath, arFolders))
    {
        return false;
    }

    int nFoldersCount = arFolders.GetCount();

    for(int i = 0; i < nFoldersCount; ++i)
    {
        if(!bFill)
        {
            m_ctrlTree.InsertItem(wsEmptyFolder, hItem, TVI_SORT);

            return false;
        }

        int nImage = m_imageList.GetImageCount();

        m_ctrlTree.InsertItem(arFolders[i], 0, 0, hItem, TVI_SORT);
    }
  
    return true;
}

void CFolderHidingToolDlg::OnTvnItemexpandingTree(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    HTREEITEM hNewItem = pNMTreeView->itemNew.hItem;

    if(pNMTreeView->action == 2)
    {
        DeleteItemsFromFolder(hNewItem);

        AddNewItemsToTree(hNewItem);
    }

    if(pNMTreeView->action == 1)
    {
        DeleteItemsFromFolder(hNewItem);
    }
    
    *pResult = 0;
}

void CFolderHidingToolDlg::DividePath(CString &sPath1, CString &sPath2, int nStart)
{
    int nPathLength = sPath1.GetLength();
    int nNeedLength = sPath1.Find(L"\\");
    int nDivide = nNeedLength;

    while(nNeedLength < nStart && nNeedLength != -1)
    {
        nDivide = nNeedLength;
        nNeedLength = sPath1.Find(L"\\", nNeedLength+1);    
    }

    sPath2 = L"    " + sPath1.Right(nPathLength-nDivide);
    sPath1.Delete(nDivide, nPathLength-nDivide);
  
}

void CFolderHidingToolDlg::OnBnClickedHideButton()
{
    HTREEITEM hSelected = m_ctrlTree.GetSelectedItem();

    if(hSelected)
    {
        if(m_ctrlTree.GetNextItem(hSelected, TVGN_PARENT))
        {
            CString sPath = GetTreePath(hSelected);
            
            LVFINDINFO info;

            info.flags = LVFI_STRING;
            info.psz = sPath;

            if(m_ctrlList.FindItem(&info) != -1)
            {
                MessageBox(L"The folder you are trying to add already exist", L"Error", MB_OK | MB_ICONSTOP);
            }
            else
            {
                int nCount = m_ctrlList.GetItemCount();

                if(nCount > 0 && m_ctrlList.GetItemText(nCount - 1, 0) == wsEmptyList)
                {
                    m_ctrlList.DeleteItem(nCount - 1);
                    
                    nCount--;
                }

                m_ctrlList.InsertItem(nCount, sPath);
            }
        }
    }


}

void CFolderHidingToolDlg::OnBnClickedShowButton()
{
    UINT nSelPosition = m_ctrlList.GetNextItem(-1, LVNI_SELECTED);

    if(nSelPosition >= 0)
    {
        UINT nCount = m_ctrlList.GetSelectedCount();

        while(nCount)
        {
            m_ctrlList.DeleteItem(nSelPosition);

            nSelPosition = m_ctrlList.GetNextItem(-1, LVNI_SELECTED);

            nCount--;
        }        
    }
}

LRESULT CFolderHidingToolDlg::OnRefreshVolumeList(WPARAM wParam, LPARAM lParam)
{
    HTREEITEM hItem = m_ctrlTree.GetRootItem();
    HTREEITEM hSelected = m_ctrlTree.GetSelectedItem();
    
    while(hItem)
    {
        if(!FillDirecoryInTree(hItem))
        {
            EmptyVolumeInTree(hItem);
        }
    
        m_ctrlTree.SelectItem(hItem);
        hItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXT);
    }
    
    CStringArray arVolumesList;
    GetVolumesList(arVolumesList);

    RefreshRootIconsAndNames(arVolumesList);

    m_ctrlTree.SelectItem(hSelected);   

    return 0;
}

LRESULT CFolderHidingToolDlg::OnRefreshTree(WPARAM wParam, LPARAM lParam)
{
    CStringArray arVolumesList;

    if(!GetVolumesList(arVolumesList))
    {
        return 0;
    }

    if(!GetValidVolumes(arVolumesList))
    {
        return 0;
    }

    int nChangedVolume = static_cast<int>(wParam);
    
    HTREEITEM hItem = m_ctrlTree.GetRootItem();
    
    while (hItem)
    {
        CString sName = GetTreePath(hItem);

        if(arVolumesList[nChangedVolume] == sName)
        {
            RefreshDrive(hItem);
            break;
        }

        hItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXT);
    }

    return 0;
}

LRESULT CFolderHidingToolDlg::AddNewVolume(WPARAM wParam, LPARAM lParam)
{
    CStringArray arVolumesList;

    if(GetVolumesList(arVolumesList))
    {
        HTREEITEM hItem = m_ctrlTree.GetRootItem();
        int nCount = arVolumesList.GetCount();

        while(hItem)
        {
            CString sVolume = GetTreePath(hItem);
            HTREEITEM hNextItem = NULL;

            int i = 0;

            while(i < nCount)
            {
                if(sVolume == arVolumesList[i])
                {
                    arVolumesList.RemoveAt(i);

                    nCount--;

                    break;
                }

                ++i;

                if(i == nCount)
                {
                    hNextItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXT);

                    m_ctrlTree.DeleteItem(hItem);
                }
            }

            if(hNextItem)
            {
                hItem = hNextItem;
            }
            else
            {
                hItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXT);
            }

            if(hItem && nCount == 0)
            {
                m_ctrlTree.DeleteItem(hItem);

                break;
            }
        }

        nCount = arVolumesList.GetCount();

        if(nCount)
        {
            hItem = m_ctrlTree.GetRootItem();

            while(hItem)
            {
                m_ctrlTree.SetItemText(hItem, GetTreePath(hItem));

                hItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXT);
            }

            for(int i=0; i < nCount; ++i)
            {
                hItem = m_ctrlTree.InsertItem(arVolumesList[i], TVI_ROOT, TVI_SORT);

                FillTreeWithFolders(arVolumesList[i], hItem, false); 
            }

            GetVolumesList(arVolumesList);

            RefreshRootIconsAndNames(arVolumesList);
        }

        return true;
    }

    return false;
}

bool CFolderHidingToolDlg::FillDirecoryInTree(HTREEITEM hItem)
{
    if(m_ctrlTree.ItemHasChildren(hItem))
    {
        return false;
    }

    CFileFind CSearchFile;
    CString sName = GetTreePath(hItem);

    BOOL bResult = CSearchFile.FindFile(sName + L"*");
    
    if(bResult)
    {
        
        FillTreeWithFolders(sName, hItem, false);
    
        return true;
    }

    return false;
}

bool CFolderHidingToolDlg::EmptyVolumeInTree(HTREEITEM hItem)
{
    if(!m_ctrlTree.ItemHasChildren(hItem))
    {
        return false;
    }

    CFileFind CSearchFile;
    CString sName = GetTreePath(hItem);

    BOOL bResult = CSearchFile.FindFile(sName + L"*");

    if(!bResult)
    {
        HTREEITEM hChildItem = m_ctrlTree.GetNextItem(hItem, TVGN_CHILD);

        while(hChildItem)
        {
            m_ctrlTree.DeleteItem(hChildItem);

            hChildItem = m_ctrlTree.GetNextItem(hItem, TVGN_CHILD);
        }

        return true;
    }

    return false;
}

bool CFolderHidingToolDlg::DeleteItemsFromFolder(HTREEITEM hItem)
{
    HTREEITEM hChildItem = m_ctrlTree.GetNextItem(hItem, TVGN_CHILD);
    
    while(hChildItem)
    {
        m_ctrlTree.DeleteItem(hChildItem);
        
        hChildItem = m_ctrlTree.GetNextItem(hItem, TVGN_CHILD);

    }

    m_ctrlTree.InsertItem(L"New", hItem, TVI_SORT);

    return true;
}

bool CFolderHidingToolDlg::AddNewItemsToTree(HTREEITEM hItem)
{
    HTREEITEM hChildItem = m_ctrlTree.GetNextItem(hItem, TVGN_CHILD);

    if(hChildItem)
    {
        m_ctrlTree.DeleteItem(hChildItem);
    }

    CString sPath = GetTreePath(hItem);
    int nCount = sPath.GetLength();

    if(sPath.Find('\\', nCount -1) == -1)
    {
        sPath += L"\\";
    }

    FillTreeWithFolders(sPath, hItem);

    hChildItem = m_ctrlTree.GetNextItem(hItem, TVGN_CHILD);
    
    while(hChildItem)
    {
        CString sFolder = m_ctrlTree.GetItemText(hChildItem);

        FillTreeWithFolders(sPath+sFolder+L"\\", hChildItem, false);

        hChildItem = m_ctrlTree.GetNextItem(hChildItem, TVGN_NEXT);
    }

    return true;
}

void CFolderHidingToolDlg::OnMainMenuExit()
{
    ASSERT(AfxGetMainWnd() != NULL);
    AfxGetMainWnd()->SendMessage(WM_CLOSE);
}

void CFolderHidingToolDlg::OnMainMenuAbout()
{
    CDialog aboutDlg(IDD_ABOUTBOX);

    INT_PTR nRet = -1;
    nRet = aboutDlg.DoModal();

    if(nRet == -1)
    {
        AfxMessageBox(L"Dialog box could not be created!");
    }
}

void CFolderHidingToolDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);

    if(nType != SIZE_MINIMIZED)
    {
        if(m_bar)
        {
            CRect rectBar, rect;
            m_bar.GetItemRect(0, &rectBar);  

            GetClientRect(&rect);

            m_bar.SetPaneInfo(0,ID_PATH_INDICATOR, SBPS_NORMAL, rect.Width()-100);      
            m_bar.SetPaneInfo(1, ID_TOOL_INDICATOR, SBPS_STRETCH, 0);

            RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_RESIZE_BAR ,ID_TOOL_INDICATOR,  reposExtra, NULL, NULL, TRUE);

            CWnd* pList = GetDlgItem(IDC_LIST);

            if(pList)
            {
                CRect rectList;                 

                pList->GetWindowRect(&rectList); 
                ScreenToClient(&rectList);      

                pList->MoveWindow(rectList.left, rectList.top, cx - rectList.left, cy - rectList.top - rectBar.bottom);
            }

            CWnd* pTree = GetDlgItem(IDC_TREE);

            if(pTree)
            {
                CRect rectTree;                 

                pTree->GetWindowRect(&rectTree); 
                ScreenToClient(&rectTree);      

                pTree->MoveWindow(rectTree.left, rectTree.top, rectTree.right, cy - rectTree.top - rectBar.bottom);
            }
        }
    }
}

bool CFolderHidingToolDlg::GetFolderIcon(const CStringArray &arString)
{
    CFileFind CSearchFile;

    for(int i = arString.GetCount() - 1; i >= 0; i--)
    {
        BOOL bResult = CSearchFile.FindFile(arString[i] + L"*");

        while(bResult)
        {
            bResult = CSearchFile.FindNextFile();

            if(CSearchFile.IsDirectory())
            {
                CString sFolder = CSearchFile.GetFileName();

                SHFILEINFO shFolder;
                memset(&shFolder, 0, sizeof(shFolder));

                ::SHGetFileInfo(arString[i] + sFolder + L"\\", 0, &shFolder, sizeof(shFolder), SHGFI_ICON | SHGFI_SMALLICON);

                if(shFolder.hIcon != NULL)
                {
                    m_imageList.Add(shFolder.hIcon);
                    DestroyIcon(shFolder.hIcon);

                    return true;
                }
            }
        }
    } 

    return false;
}

bool CFolderHidingToolDlg::RefreshRootIconsAndNames(CStringArray &arRootItems)
{
    int nImageCount = m_imageList.GetImageCount();

    while(nImageCount > 1)
    {
        m_imageList.Remove(nImageCount - 1);
        nImageCount--;
    }

    HTREEITEM hItem = m_ctrlTree.GetRootItem();
    SHFILEINFO shDrive;
    int nDriveCount = arRootItems.GetCount();

    for(int i = 0; i < nDriveCount; ++i)
    {
        memset(&shDrive, 0, sizeof(shDrive));
        ::SHGetFileInfo(arRootItems[i], 0, &shDrive, sizeof(shDrive), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME);

        if(shDrive.hIcon != NULL)
        {
            m_imageList.Add(shDrive.hIcon);
            DestroyIcon(shDrive.hIcon);

            int nImage = m_imageList.GetImageCount();

            m_ctrlTree.SetItemImage(hItem, nImage - 1, nImage - 1);

        }

        if(shDrive.szDisplayName != L"")
        {
            m_ctrlTree.SetItemText(hItem, shDrive.szDisplayName);
        }

        hItem = m_ctrlTree.GetNextItem(hItem, TVGN_NEXT); 
    }

    return true;
}

void CFolderHidingToolDlg::OnBnClickedApplyButton()
{
    int nCount = m_ctrlList.GetItemCount();

    if(nCount)
    {
        if(nCount == 1)
        {
            CString sItem = m_ctrlList.GetItemText(0, 0);

            if(sItem == L"")
            {
                m_ctrlList.InsertItem(0, wsEmptyList);
            }
        }
    }
    else
    {
        m_ctrlList.InsertItem(0, wsEmptyList);
    }
    
    CMultiSZObserver observer(&m_ctrlList);
  
    try
    {
        WriteMultiSZValue(wsKeyValue, wsKeyName, observer.GetVector());
    }
    catch (...) 
    {
        MessageBox(L"Can't write list of hiden folders", L"Error", MB_OK | MB_ICONERROR);
    }

    if(!NotificateDriver())
    {
        MessageBox(L"List refresh failed, coudln't sent message to driver", L"Error", MB_OK | MB_ICONERROR);
    }

    HTREEITEM hRootItem = m_ctrlTree.GetRootItem();

    while(hRootItem)
    {
        HTREEITEM hChild = m_ctrlTree.GetNextItem(hRootItem, TVGN_CHILD);
        
        if(hChild)
        {
            RefreshDrive(hRootItem);
        }
        else
        {
            CString sPath = GetTreePath(hRootItem);
            FillTreeWithFolders(sPath, hRootItem, true);
            
            HTREEITEM hChild = m_ctrlTree.GetNextItem(hRootItem, TVGN_CHILD);

            while(hChild)
            {
                sPath = GetTreePath(hChild);
                FillTreeWithFolders(sPath, hChild, false);

                hChild = m_ctrlTree.GetNextItem(hChild, TVGN_NEXT);
            }
        }

        hRootItem = m_ctrlTree.GetNextItem(hRootItem, TVGN_NEXT);
    }

}

void CFolderHidingToolDlg::ClearRulesList(void)
{
    if(m_ctrlList.GetItemText(0, 0) == wsEmptyList)
    {
        m_ctrlList.DeleteAllItems();

        return;
    }

    int nListCount = m_ctrlList.GetItemCount();
    int i = 0;

    while(i < nListCount)
    {
        CString sRule = m_ctrlList.GetItemText(i, 0);

        if(sRule == L"")
        {
            m_ctrlList.DeleteItem(i);

            nListCount--;
        }
        else
        {
            CFileFind CSearchFile;

            BOOL bResult = CSearchFile.FindFile(sRule + L"\\*");

            if(!bResult)
            {
                m_ctrlList.DeleteItem(i);

                nListCount--;
            }
            else
            {
                i++;
            }

            CSearchFile.Close();
        }
    }
}

bool CFolderHidingToolDlg::NotificateDriver(void)
{
    HANDLE hDriverHandle = CreateFileW( FileHidingFilterCDONameForUser,
                                        GENERIC_READ | GENERIC_WRITE,
                                        0,
                                        NULL,
                                        OPEN_EXISTING,
                                        FILE_ATTRIBUTE_NORMAL,
                                        NULL);

    if (INVALID_HANDLE_VALUE == hDriverHandle)
    {
        return false;
    }

    DWORD dwBytesReturned = 0;

    if (    !DeviceIoControl(hDriverHandle,
                            IOCTL_FHF_RELOAD_RULES,
                            NULL,
                            0,
                            NULL,
                            0,
                            &dwBytesReturned,
                            NULL))
    {
        CloseHandle(hDriverHandle);

        return false;
    }

    CloseHandle(hDriverHandle);
    
    return true;    
}

bool CFolderHidingToolDlg::RefreshTree(HTREEITEM hRootItem)
{
    HTREEITEM hVisibleItem = m_ctrlTree.GetNextVisibleItem(hRootItem);
    HTREEITEM hChildItem = m_ctrlTree.GetNextItem(hRootItem, TVGN_CHILD);
    
    if(hVisibleItem != hChildItem || !hVisibleItem)
    {
        return false;
    }

    CStringArray arCurentFolders;
    
    do 
    {
        CString sPathForSearch = GetTreePath(hChildItem);
        CFileFind CSearchFile;

        BOOL bResult = CSearchFile.FindFile(sPathForSearch);

        if(!bResult)
        {
            HTREEITEM hItemToDelete = hChildItem;

            hChildItem = m_ctrlTree.GetNextItem(hChildItem, TVGN_NEXT);

            m_ctrlTree.DeleteItem(hItemToDelete);
        }
        else
        {
            arCurentFolders.Add(m_ctrlTree.GetItemText(hChildItem));
            
            hChildItem = m_ctrlTree.GetNextItem(hChildItem, TVGN_NEXT);
        }

    } while (hChildItem);

    CStringArray arNewFolders;
    CString sPathForSearch = GetTreePath(hRootItem);
    int nCount = sPathForSearch.GetLength();

    if(sPathForSearch.Find('\\', nCount -1) == -1)
    {
        sPathForSearch += L"\\";
    }

    GetFoldersInDirectory(sPathForSearch, arNewFolders);
    DivideStringArrays(arNewFolders, arCurentFolders);

    int nNewItemsCount = arNewFolders.GetCount();

    if(nNewItemsCount)
    {
        do 
        {
            nNewItemsCount--;
            
            HTREEITEM hItem = m_ctrlTree.InsertItem(arNewFolders[nNewItemsCount], 0, 0, hRootItem, TVI_SORT);

            sPathForSearch = GetTreePath(hItem);

            FillTreeWithFolders(sPathForSearch, hItem, false);

        } while (nNewItemsCount);
    }

    return true;

}

bool CFolderHidingToolDlg::RefreshDrive(HTREEITEM hDrive)
{
    if(RefreshTree(hDrive))
    {
        HTREEITEM hVisibleItem = m_ctrlTree.GetNextVisibleItem(hDrive);

        while(hVisibleItem)
        {
            if(!m_ctrlTree.GetParentItem(hVisibleItem))
            {
                break;
            }
            
            CString sPathForSearch = GetTreePath(hVisibleItem);
            CFileFind CSearchFile;

            BOOL bResult = CSearchFile.FindFile(sPathForSearch);

            if(!bResult)
            {
                HTREEITEM hItemToDelete = hVisibleItem;

                hVisibleItem = m_ctrlTree.GetNextItem(hVisibleItem, TVGN_NEXT);

                m_ctrlTree.DeleteItem(hItemToDelete);
            }
            else
            {
                RefreshTree(hVisibleItem);

                hVisibleItem = m_ctrlTree.GetNextVisibleItem(hVisibleItem);
            }
        }

        return true;
    }

    return false;
}
